
package view;

import controllers.CheckSyntacticValidationProgressTask;
import controllers.HelpContentControl;
import controllers.InitialValues;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuBar;
import javafx.scene.control.MenuItem;
import javafx.scene.control.SeparatorMenuItem;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyCodeCombination;
import javafx.scene.input.KeyCombination;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
import ws.login.NormalizedEstablishment;

/**
 * @version 1.0
 * @date 10/04/2012
 * @author john
 */
public class MainWindow extends Application {
    
    private static Task syntacticFileAnalysis;
    private static Task semanticFileAnalysis;
    private String filePath="";
    private long fileLinesNumber=-1;
    private static NormalizedEstablishment activeUser;
    private InitialValues initialValues;
    
    private static Stage loginDialog;
    private static Stage loginContactDialog;
    private static Stage contactDialog;
    private static Stage aboutDialog;
    private GridPane loadFilePane;
    private GridPane statsPane;
    private GridPane progressPane;
    private GridPane reportHistoryPane;
    private double defaultWidth=1000;
    private double defaultHeight=650;
    
    private Group root;
    private Scene scene;
    private BorderPane borderPane;
    private static MenuBar menuBar;
    private static Menu fileM;
    private static Menu reportsM;
    private static Menu helpM;
    private static MenuItem loadMI;
    private static MenuItem loadStateMI;
    private static MenuItem fullscreenMI;
    private static MenuItem exitMI;
    private static MenuItem newReportMI;
    private static MenuItem openReportsHistoryMI;
    private static MenuItem contentMI;
    private static MenuItem contactMI;
    private static MenuItem aboutMI;
    
    private static Stage primaryStage;
    
    @Override
    public void start(Stage primaryStage) {
        MainWindow.primaryStage=primaryStage;
        primaryStage.setTitle("SATAcredito");
        root=new Group();
        scene=new Scene(root, defaultWidth, defaultHeight, Color.WHITE);
        scene.getStylesheets().add("view/styles.css");
        initMenu(primaryStage);
        borderPane=new BorderPane();
        borderPane.setTop(menuBar);
        loginDialog=new LoginDialog(primaryStage);
        loginDialog.sizeToScene();
        loadFilePane = new LoadFilePane(primaryStage,this);
        progressPane=new ProgressPane(primaryStage, this, "", 0);
        root.getChildren().addAll(borderPane);
        primaryStage.setScene(scene);
        primaryStage.setOnCloseRequest(finishApplication());
        primaryStage.show();
        new Thread(new Runnable() {
            @Override
            public void run() {
                initialValues = new InitialValues();
            }
        }).start();
        showLoginDialog();
    }
    
    /**
     * Inizializa el menu principal
     * @param primaryStage 
     */
    private void initMenu(final Stage primaryStage){
        menuBar=new MenuBar();
        menuBar.prefWidthProperty().bind(scene.widthProperty());
        initFileMenu(primaryStage);
        initReportsMenu(primaryStage);
        initHelpMenu(primaryStage);
        menuBar.getMenus().setAll(fileM,reportsM,helpM);
    }
    
    /**
     * Inizializa los menus del archivo
     * @param primaryStage 
     */
    private void initFileMenu(final Stage primaryStage){
        fileM=new Menu("Archivo");
        loadMI=new MenuItem("Cargar archivo");
        loadStateMI=new MenuItem("Ver estado de carga");
        fullscreenMI=new MenuItem("Pantalla Completa");
        exitMI=new MenuItem("Salir");
        loadMI.setOnAction(loadFile());
        loadStateMI.setOnAction(seeLoadState());
        fullscreenMI.setOnAction(fullScreen(primaryStage));
        exitMI.setOnAction(exit());
        loadMI.setAccelerator(new KeyCodeCombination(KeyCode.L, KeyCombination.CONTROL_DOWN));
        fullscreenMI.setAccelerator(new KeyCodeCombination(KeyCode.F, KeyCombination.CONTROL_DOWN));
        exitMI.setAccelerator(new KeyCodeCombination(KeyCode.Q, KeyCombination.CONTROL_DOWN));
        fileM.getItems().setAll(
            loadMI,
            loadStateMI,
            new SeparatorMenuItem(),
            fullscreenMI,
            new SeparatorMenuItem(),
            exitMI
        );
    }
    
    /**
     * Inizializa los menus para reportes
     * @param primaryStage 
     */
    private void initReportsMenu(final Stage primaryStage){
        reportsM=new Menu("Reportes");
        newReportMI=new MenuItem("Nuevo reporte");
        openReportsHistoryMI=new MenuItem("Ver historial de reportes");
        newReportMI.setOnAction(newReport(primaryStage));
        openReportsHistoryMI.setOnAction(openReportsHistory());
        newReportMI.setAccelerator(new KeyCodeCombination(KeyCode.R, KeyCombination.CONTROL_DOWN));
        openReportsHistoryMI.setAccelerator(new KeyCodeCombination(KeyCode.H, KeyCombination.CONTROL_DOWN));
        reportsM.getItems().setAll(newReportMI,openReportsHistoryMI);
    }
    
    /**
     * Inizializa los menus de ayuda
     * @param primaryStage 
     */
    private void initHelpMenu(final Stage primaryStage){
        helpM=new Menu("Ayuda");
        contentMI=new MenuItem("Contenido");
        contactMI=new MenuItem("Contacto");
        aboutMI=new MenuItem("Acerca");
        contentMI.setOnAction(showContent());
        contactMI.setOnAction(contactAction(primaryStage));
        aboutMI.setOnAction(aboutAction());
        contentMI.setAccelerator(new KeyCodeCombination(KeyCode.F1, KeyCombination.CONTROL_DOWN));
        helpM.getItems().setAll(contentMI,contactMI,new SeparatorMenuItem(),aboutMI);
    }
    
    /**
     * Inicializa los hilos para la comenzar el analisis de un archivo
     * @param filePath
     * @param numberOfLinesFile 
     */
    protected void startFileAnalysis(String filePath, long numberOfLinesFile){
        this.filePath=filePath;
        this.fileLinesNumber=numberOfLinesFile;
        progressPane=new ProgressPane(primaryStage, this, filePath, numberOfLinesFile);
        syntacticFileAnalysis=((ProgressPane)progressPane).createSyntacticValidationTask();
        semanticFileAnalysis=((ProgressPane)progressPane).createSemanticValidationTask();
        final Thread doSyntacticAnalysis = new Thread(syntacticFileAnalysis);
        final Thread doSemanticAnalysis = new Thread(semanticFileAnalysis);
        doSyntacticAnalysis.setDaemon(true);
        doSemanticAnalysis.setDaemon(true);
        ((CheckSyntacticValidationProgressTask)syntacticFileAnalysis).getTheValidatorThread().progressProperty().addListener(new ChangeListener<Number>() {
            @Override
            public void changed(ObservableValue<? extends Number> ov, Number oldValue, Number newValue) {
                if(newValue.doubleValue()==1.0){
                    ((ProgressPane)progressPane).setFileID(((ProgressPane)progressPane).getArchiveID());
                    ((ProgressPane)progressPane).setTotalSendLinesNumber(((ProgressPane)progressPane).getValidLinesNumber());
                    doSemanticAnalysis.start();
                }
            }
        });
        doSyntacticAnalysis.start();
        loadStateMI.fire();
    }
    
    /**
     * Finaliza el analisis de un archivo y habilita el menu para subir otro
     */
    protected void endFileAnalysis(){
        this.filePath="";
        this.fileLinesNumber=-1;
        ((LoadFilePane)loadFilePane).enableLoad();
    }
    
    /**
     * Muestra la GUI para cargar un archivo
     * @return 
     */
    private EventHandler<ActionEvent> loadFile(){
        return new EventHandler<ActionEvent>(){
            @Override
            public void handle(ActionEvent event) {
                borderPane.setCenter(loadFilePane);
            }
        };
    }
    
    /**
     * Muestra la GUI del progreso de validacion y carga de un archivo
     * @return 
     */
    private EventHandler<ActionEvent> seeLoadState(){
        return new EventHandler<ActionEvent>(){
            @Override
            public void handle(ActionEvent event) {
                borderPane.setCenter(progressPane);
            }
        };
    }
    
    /**
     * Pantalla completa
     * @param primaryStage
     * @return 
     */
    private EventHandler<ActionEvent> fullScreen(final Stage primaryStage){
        return new EventHandler<ActionEvent>(){
            @Override
            public void handle(ActionEvent event) {
                primaryStage.setFullScreen(!primaryStage.isFullScreen());
            }
        };
    }
    
    /**
     * Termina la aplicacion
     * @return 
     */
    private EventHandler<ActionEvent> exit(){
        return new EventHandler<ActionEvent>(){
            @Override
            public void handle(ActionEvent event) {
                if(syntacticFileAnalysis!=null && syntacticFileAnalysis.isRunning())
                    syntacticFileAnalysis.cancel(true);
                if(semanticFileAnalysis!=null && semanticFileAnalysis.isRunning())
                    semanticFileAnalysis.cancel(true);
                Platform.exit();
                System.exit(0);
            }
        };
    }
    
    /**
     * Muestra la GUI para crear un nuevo reporte/estadisticas
     * @return 
     */
    private EventHandler<ActionEvent> newReport(final Stage stage){
        return new EventHandler<ActionEvent>(){
            @Override
            public void handle(ActionEvent event) {
                statsPane=new StatsPane(stage);
                borderPane.setCenter(statsPane);
            }
        };
    }
    
    /**
     * Muestra la GUI del hisotorial de reportes generados
     * @return 
     */
    private EventHandler<ActionEvent> openReportsHistory(){
        return new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent arg0) {
                if(reportHistoryPane==null)
                    reportHistoryPane=new ReportHistory(primaryStage);
                borderPane.setCenter(reportHistoryPane);
                ((ReportHistory)reportHistoryPane).fillTable();
            }
        };
    }
    
    /**
     * Muestra la GUI de informacion de ayuda
     * @return 
     */
    private EventHandler<ActionEvent> showContent(){
        return new EventHandler<ActionEvent>(){
            @Override
            public void handle(ActionEvent event) {
                boolean explorerFound=HelpContentControl.openDocumentation();
                if(!explorerFound)
                    new ExplorerErrorDialog(primaryStage).show();
            }
        };
    }
    
    /**
     * Muestra la GUI de contacto
     * @return 
     */
    private EventHandler<ActionEvent> contactAction(final Stage primaryStage){
        return new EventHandler<ActionEvent>(){
            @Override
            public void handle(ActionEvent event) {
                if(contactDialog==null)
                    contactDialog=new ContactDialog(primaryStage, false);
                contactDialog.show();
            }
        };
    }
    
    /**
     * Muestra la GUI con la informacion de la aplicacion
     * @return 
     */
    private EventHandler<ActionEvent> aboutAction(){
        return new EventHandler<ActionEvent>(){
            @Override
            public void handle(ActionEvent event) {
                if(aboutDialog==null)
                    aboutDialog=new AboutDialog(primaryStage);
                aboutDialog.show();
            }
        };
    }
    
    /**
     * 
     * @param newState 
     */
    protected static void changeMenuItemsState(boolean newState){
        loadMI.setDisable(!newState);
//        loadStateMI.setDisable(!newState);
    }

    public static NormalizedEstablishment getActiveUser() {
        return activeUser;
    }

    public static void setActiveUser(NormalizedEstablishment activeUser) {
        MainWindow.activeUser = activeUser;
    }
    
    /**
     * 
     * @return 
     */
    private EventHandler<WindowEvent> finishApplication(){
        return new EventHandler<WindowEvent>() {
            @Override
            public void handle(WindowEvent event) {
                event.consume();
                exitMI.fire();
            }
        };
    }
    
    /**
     * 
     */
    public static void showLoginDialog(){
        ((LoginDialog)loginDialog).showStage();
    }
    
    /**
     * 
     */
    public static void closeLoginDialog(){
        ((LoginDialog)loginDialog).closeDialog();
    }
    
    /**
     * 
     */
    public static void showLoginContactDialog(){
        if(loginContactDialog==null){
            loginContactDialog=new ContactDialog(primaryStage,true);
            loginContactDialog.sizeToScene();
        }
        ((ContactDialog)loginContactDialog).showStage();
    }
    
    /**
     * 
     */
    public static void closeLoginContactDialog(){
        loginContactDialog.close();
    }
    
    /**
     * 
     */
    public static void showLoadPane(){
        loadMI.fire();
    }
    
    public static void main(String[]args){
        launch(args);
    }
    
}